home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / business / pcprojct.zip / PROJECT.ZOO / classes / projwind.cls < prev    next >
Text File  |  1990-05-24  |  30KB  |  1,063 lines

  1. /* Maintain a Project chart in a Window. The ProjWindow is
  2.    responsible for all drawing of the project. The window 
  3.    has full scrolling and supports a keyboard interface.
  4.    If topMethod or botMethod are set, then the corresponding
  5.    method will be executed for each activity while displaying
  6.    the project.
  7.  
  8.    ProjWindow descends from class Window and inherits all of
  9.    its instance variables and methods.
  10.  
  11.    All strings are defined as resources for easy translation.
  12. */!!
  13.  
  14. inherit(Window, #ProjWindow, #(project     /* the project */
  15. fileName    /* of the project */
  16. actions     /* menu actions table */
  17. dirty       /* true if not saved */
  18. view        /* normal or zoomed */
  19. boxHeight   /* based on scrnsize */
  20. boxWidth    /* adjustable for zoom */
  21. boxHSpace   /* adjustable */
  22. activWidth  /* adjustable */
  23. hScrollPos  /* horiz scroll posn */
  24. vScrollPos  /* vert scroll posn */
  25. maxVisCol   /* max visible col */
  26. maxVisRow   /* max visible row */
  27. methTable   /* table of methods */
  28. topMethod   /* offset into table */
  29. botMethod   /* offset into table */
  30. gw          /* a GanttWindow */
  31. /* these are new for dragging */
  32. dragDC      /* for drawing */
  33. anchorPt    /* starting point */
  34. oldPt       /* end point */
  35. ), 2, nil)!!
  36.  
  37. now(ProjWindowClass)!!
  38.  
  39. /* Return the name of this class's MS-Windows window class
  40.   either for registration or new window creation. */
  41. Def wndClass(self)
  42. { ^"ProjWindow"  }!!
  43.  
  44. /* Create a new window class Struct.
  45.    Change the cursor to a cross.  */
  46. Def newWClass(self, lpCl, lpIcon | wc)
  47. { wc := newWClass(self:WindowClass, lpCl, lpIcon);
  48.   putWord(wc, Call LoadCursor(0, IDC_CROSS), 14);
  49.   ^wc;
  50. } !!
  51.  
  52. now(ProjWindow)!!
  53.  
  54. /* Allow the user to change the printer setup. */
  55. Def printerSetup(self | prn)
  56.   prn := new(Printer);
  57.   getPrinterParms(prn);
  58.   deviceMode(prn, self);
  59. }
  60. !!
  61.  
  62. /* Respond to menu choice to run a program. 
  63.    By default, run MSDOS executive shell.*/
  64. Def run(self | dlg, progName)
  65. {
  66.   dlg := new(InputDialog, "Run","Program name:","MSDOS.EXE");
  67.   if runModal(dlg, INPUT_BOX, self) == IDOK
  68.     progName:=getText(dlg);
  69.     exec(progName);
  70.   endif;
  71. }!!
  72.  
  73. /* Handles menu choice to set colors. Global variables
  74.    CritColor and SlackColor determine the application
  75.    colors. */
  76. Def toggleColor(self)
  77. {
  78.   if CritColor <> BLACK
  79.     unCheckMenuItem(self, PW_COLOR);
  80.     CritColor := BLACK;
  81.     SlackColor := BLACK;
  82.   else
  83.     checkMenuItem(self, PW_COLOR);
  84.     CritColor := RED;
  85.     SlackColor := BLUE;
  86.   endif;
  87.   invalidate(self);
  88.   if gw invalidate(gw); endif;
  89. }!!
  90.  
  91. /* Create a new Milestone */
  92. Def newMilestone(self)
  93. {
  94.   newActivity(self, Milestone);
  95. }!!
  96.  
  97. /* Create the window using a "main" window style. */
  98. Def create(self, par, wName, rect, style)
  99.   ^create(self:Window, nil, wName, rect, 
  100.      WS_OVERLAPPEDWINDOW bitOr WS_VSCROLL bitOr WS_HSCROLL);
  101. }!!
  102.  
  103. /* Set up a dummy project, menus and the method table. */
  104. Def init(self)
  105. {  
  106.   setProject(self, new(Project));
  107.   setAutoCalc(project, true);  
  108.   setView(self, #normal);
  109.   setScrollBars(self);
  110.   setMenus(self);
  111.   checkMenuItem(self, PW_AUTOCALC);
  112.   checkMenuItem(self, PW_COLOR);
  113.   setMethTable(self);
  114. }!!
  115.  
  116. /* Set the project. */
  117. Def setProject(self, aProject)
  118. {
  119.   project := aProject;
  120. }!!
  121.  
  122. /* Set the resolution for the size of nodes, spacing etc.
  123.    based on the font text size.  There are two views,
  124.    normal and small.  Both are based on text font size so
  125.    that they will display adequately with any resolution. */
  126. Def setView(self, aView | hDC, ts)
  127. {
  128.   view := aView;
  129.   hDC := getContext(self);    /* so we can get text size */
  130.   ts := textSize(self, hDC);  /* x is width, y is height */
  131.   releaseContext(self, hDC);
  132.   if view == #small
  133.     boxWidth := x(ts) * 4;
  134.     boxHSpace := x(ts)/2 + 1;
  135.     boxHeight := y(ts) + 4;
  136.   else
  137.     boxWidth := asInt(x(ts)*8);
  138.     boxHSpace := x(ts) + 2;
  139.     boxHeight := y(ts) * 2;   
  140.   endif;
  141.   activWidth := boxWidth + boxHSpace;
  142.   reSize(self, 0, 0L);        /* so scrolling is adjusted */
  143. }!!
  144.  
  145. /* Set the scroll bar ranges and initial positions. */
  146. Def setScrollBars(self)
  147.   Call SetScrollRange(hWnd, SB_HORZ, 0, PW_MAX_COLS, 0);
  148.   Call SetScrollRange(hWnd, SB_VERT, 0, PW_MAX_ROWS, 0);
  149.   hScrollPos := vScrollPos := 0; 
  150. }!!
  151.  
  152. /* Set up the method table used for display options. 
  153.    Each of these methods should be applicable to all
  154.    activities in the project, that is, both Milestones
  155.    and Tasks. */
  156. Def setMethTable(self)
  157. {
  158.     methTable := #(#getTime, 
  159.                    #getSlack, 
  160.                    #getCost,
  161.                    #getEarlyStart,
  162.                    #getEarlyFinish,
  163.                    #getLateStart,
  164.                    #getLateFinish);
  165.   topMethod := 3;
  166. }!!
  167.  
  168. /* Set the method to display info below each box. 
  169.    The offset refers to the position in the
  170.    methTable. */
  171. Def setBotMethod(self, offset)
  172. {
  173.   botMethod := offset;
  174. }!!
  175.  
  176. /* Set the method to display info atop each box. 
  177.    The offset refers to the position in the
  178.    methTable. */
  179. Def setTopMethod(self, offset)
  180. {
  181.   topMethod := offset;
  182. }!!
  183.  
  184. /* Add an about box and load menu resources.
  185.    Set up the menu actions table. Each entry
  186.    consists of a constant ID and a message
  187.    that will be performed. */
  188. Def setMenus(self)
  189. {
  190.   addAbout(self);
  191.   loadMenu(self, "PWMenus");
  192.   setMenu(self, hMenu);
  193.  
  194.   actions := new(Dictionary, 30);
  195.  
  196.   add(actions, PW_FILE_NEW, #fileNew);
  197.   add(actions, PW_FILE_OPEN, #fileOpenAs);
  198.   add(actions, PW_FILE_SAVE, #fileSave);
  199.   add(actions, PW_FILE_SAVEAS, #fileSaveAs);
  200.   add(actions, PW_FILE_PRINT, #print);
  201.   add(actions, PW_FILE_PRINT_GRAPH, #printGraphs);
  202.   add(actions, PW_FILE_SETTINGS, #printerSetup);
  203.   add(actions, PW_RUN, #run);
  204.   add(actions, PW_FILE_QUIT, #close);
  205.   add(actions, PW_CLIP, #clipChart);
  206.   add(actions, PW_ABOUT_ACTOR, #aboutActor);
  207.   add(actions, PW_DEL_ACTIVITY, #deleteActivity);
  208.   add(actions, PW_DEL_RESOURCE, #deleteResource);
  209.   add(actions, PW_NEW_MSTONE, #newMilestone);
  210.   add(actions, PW_NEW_TASK, #newTask);
  211.   add(actions, PW_NEW_PERT, #newPERTTask);
  212.   add(actions, PW_DISPLAY, #displaySettings);
  213.   add(actions, PW_COLOR, #toggleColor);
  214.   add(actions, PW_AUTOCALC, #autoCalc);
  215.   add(actions, PW_CALC, #recalc);
  216.   add(actions, PW_SHOWROOM, #showRoom);
  217.   add(actions, PW_ZOOM, #zoom);
  218.   add(actions, PW_VIEW_SUMMARY, #viewSummary);
  219.   add(actions, PW_VIEW_ACTIVITIES, #showActivities);
  220.   add(actions, PW_VIEW_GANTT, #gantt);
  221.   add(actions, PW_VIEW_RESOURCES, #showResources);
  222.   add(actions, PW_VIEW_RESOURCE, #editResource);
  223.  
  224.     /* keyboard accelerator commands */
  225.     
  226.   add(actions, PW_HELP, #help);
  227.   add(actions, EDIT_HOME, #home);
  228.   add(actions, PW_COMMAND_MODE, #commandMode);
  229. }!!
  230.  
  231. /* Convert window coordinates to relative display coordinates. */
  232. Def windowToDisplay(self, wPoint)
  233. {
  234.   ^point((x(wPoint) - boxHSpace) / activWidth  + hScrollPos,
  235.          (y(wPoint) - boxHeight) / (boxHeight*2) + vScrollPos);
  236. }!!
  237.  
  238. /* Convert relative display entries to window coordinates. 
  239.    Uses dot notation for speed. */
  240. Def displayToWindow(self, dPoint)
  241. {
  242.    ^point(boxHSpace + (dPoint.x - hScrollPos) * activWidth,
  243.           boxHeight + (dPoint.y - vScrollPos) * boxHeight*2);          
  244. }!!
  245.  
  246. /* The name of application, used for captions. */
  247. Def  appName(self)
  248.   ^loadString(PW_APPNAME);
  249. }!!
  250.  
  251. /* Check if there is a file error and display an error box. 
  252.    Return the error number, 0 for no error. */
  253. Def checkError(self, aFile | errNo)
  254. {
  255.    errNo := getError(aFile);
  256.    if errNo <> 0
  257.      beep();
  258.      errorBox(loadString(PW_FILEERR1),
  259.               loadString(PW_FILEERR2) + asString(aFile) +
  260.               loadString(PW_FILEERR3) + asString(errNo) +
  261.               loadString(50+errNo));
  262.    endif;
  263.    ^errNo;
  264. }!!
  265.  
  266. /* Returns true if the node is visible in the window.
  267.    Used to speed up redrawing. Uses dot notation for speed. */
  268. Def visible(self, aNode)
  269.   ^between(aNode.x, hScrollPos, maxVisCol + hScrollPos)
  270.      cand between(aNode.y, vScrollPos, maxVisRow + vScrollPos);
  271. }!!
  272.  
  273. /* Set up the cursor for use even if there is no mouse. */
  274. Def gotFocus(self, prevHwnd)
  275.   Call ShowCursor(1);
  276. }!!
  277.  
  278. /* Return to normal use of cursor.  */
  279. Def losingFocus(self, hWndNew)
  280.   Call ShowCursor(0);
  281. } !!
  282.  
  283. /* Check if the project has been saved. */
  284. Def shouldClose(self)
  285.   ^checkClean(self)
  286. }!!
  287.  
  288. /* Make sure the window knows that the project has changed. */
  289. Def dirty(self)
  290. {
  291.   invalidate(self);
  292.   dirty := true;
  293.   if gw
  294.     invalidate(gw);
  295.   endif;
  296. }!!
  297.  
  298. /* Returns boolean value true if the project has
  299.    not changed since last save.  If it is dirty,
  300.    the user is prompted for confirmation.  */
  301. Def checkClean(self)
  302. {
  303.   ^ not(dirty) cor 
  304.      yesNoBox(loadString(PW_WARNING),
  305.               loadString(PW_DISCARD)) == IDYES;
  306. }!!
  307.  
  308. /* Get the offset of the botMethod. */
  309. Def getBotMethod(self)
  310. {
  311.   ^botMethod;
  312. }!!
  313.  
  314. /* Get the offset of the topMethod. */
  315. Def getTopMethod(self)
  316. {
  317.   ^topMethod;
  318. }!!
  319.  
  320. /* Resize the window.  Adjust visible rows and cols. */
  321. Def reSize(self, wp, lp)
  322.   maxVisRow := bottom(clientRect(self)) / (boxHeight*2);
  323.   maxVisCol := right(clientRect(self)) / activWidth;
  324. }!!
  325.  
  326. /* Respond to MS-Windows messages to paint the window. 
  327.    Show the project as a network chart.
  328.    Draw each visible node in its proper position. 
  329.    Display the name and any other info required.
  330.    Then draw the lines to connect the outputs.
  331.    
  332.    The displayToWindow message converts a node's
  333.    logical display position to windows coordinates.
  334.    
  335.    This could be further speeded up by repainting 
  336.    only the invalid rectangle.
  337. */
  338. Def paint(self, hDC |wPoint, x, y)
  339. {
  340.   do(nodes(project), 
  341.    {using(aNode)
  342.    
  343.    wPoint := displayToWindow(self, pos(aNode));
  344.    x := x(wPoint);    /* horiz windows posn */
  345.    y := y(wPoint);    /* vert windows posn */
  346.     
  347.    if visible(self, aNode)
  348.      draw(aNode, self, x, y, hDC);  /* node knows how to draw */ 
  349.      drawTextInfo(self, aNode, x, y, hDC);
  350.    endIf;
  351.    /* always draw connections since they may be visible */
  352.    drawConnections(self, aNode, x, y, getOutputs(aNode), hDC);
  353.   }); 
  354. }!!
  355.  
  356. /* Draw lines connecting the nodes in the window. 
  357.    Uses early binding, dot notation and direct
  358.    Windows calls for speed. */
  359. Def drawConnections(self, aNode, x, y, connectedNodes, hDC | wPoint)
  360. {
  361.      do(connectedNodes,
  362.        {using(output)  
  363.         Call MoveTo(hDC,  x + boxWidth, y + boxHeight/2);
  364.         wPoint := displayToWindow(self:ProjWindow, pos(output));
  365.         Call LineTo(hDC, wPoint.x, wPoint.y + boxHeight/2);
  366.  
  367.         if critical(aNode:Activity) cand critical(output:Activity)  
  368.           Call MoveTo(hDC,  x + boxWidth, y + boxHeight/2+1);
  369.           Call LineTo(hDC, wPoint.x, wPoint.y + boxHeight/2+1);
  370.         endif;       
  371.      });   
  372. }!!
  373.  
  374. /* Draw text info in the window.  If the small view is
  375.    being used, show less information.
  376.    Uses early binding and dot notation for speed. */
  377. Def drawTextInfo(self, aNode, x, y, hDC | ts, str, strSize, offsetY, offsetX)
  378. {
  379.  ts := textSize(self, hDC);
  380.  offsetY := (boxHeight - ts.y) / 2;
  381.  strSize := boxWidth / ts.x;
  382.  if view == #small
  383.    offsetX := 2;   /* to make milestones look ok */
  384.  else
  385.    offsetX := 0;
  386.  endif;
  387.  
  388.  str := subString(aNode.name, 0, strSize-1);
  389.  Call SetTextColor(hDC, SlackColor);
  390.  Call TextOut(hDC, x + offsetX + 2, y + offsetY, str, size(str));     
  391.  
  392.  if critical(aNode)
  393.    Call SetTextColor(hDC, CritColor);
  394.  endif;
  395.  
  396.  if topMethod     /* display above box */
  397.    str := subString(asString(perform(aNode, methTable[topMethod])),0,strSize);
  398.    Call TextOut(hDC, x + 2, y - ts.y, str, size(str));
  399.  endif;
  400.  
  401.  if view ~= #small
  402.  cand botMethod     /* display below box */
  403.      str :=  subString(asString(perform(aNode, methTable[botMethod])),0,strSize);
  404.      Call TextOut(hDC, x + 2, y + boxHeight, str, size(str));
  405.  endif;
  406. }!!
  407.  
  408. /* Draw a task in the window. 
  409.    Uses early binding and direct Windows call for speed. */
  410. Def drawTask(self, aNode, x, y, hDC)
  411. {
  412.   Call Rectangle(hDC, x, y, x + boxWidth, y + boxHeight); 
  413.   if critical(aNode:Activity)
  414.     Call Rectangle(hDC, x+1, y+1, x + boxWidth-1, y + boxHeight-1);
  415.   endif;
  416. }!!
  417.  
  418. /* Draw a milestone in the window. 
  419.    Uses early binding and direct Windows call for speed. */
  420. Def drawMilestone(self, aNode, x, y, hDC)
  421. {
  422.   Call RoundRect(hDC, x, y, x + boxWidth, y + boxHeight, 20,20);
  423.   if critical(aNode:Activity)
  424.     Call RoundRect(hDC, x+1, y+1, x + boxWidth-1, y + boxHeight-1, 17,17);
  425.   endif;     
  426. }!!
  427.  
  428. /* Handle menu events, accelerator keys.
  429.    Lookup the ID in the actions table, if found
  430.    perform it.  */
  431. Def command(self, wp, lp)
  432. {
  433.   if actions[wp]
  434.     perform(self, actions[wp]);
  435.   else  /* these keys might be accelerators */
  436.     if wp == VK_UP  cor wp == VK_DOWN cor
  437.        wp == VK_RIGHT cor wp == VK_LEFT
  438.       WM_KEYDOWN(self, wp, lp);
  439.     else
  440.       beep();  /* internal error! */
  441.       errorBox(loadString(PW_ERROR1),
  442.         loadString(PW_ERROR2) + asString(wp));
  443.     endif;
  444.   endif;
  445. }!!
  446.  
  447. /* Go into "command mode" in response to a slash key accelerator.
  448.    This simulates Lotus 1-2-3 style commands by sending an
  449.    ALT key sysCommand message. */
  450. Def commandMode(self)
  451.   WM_SYSCOMMAND(self, 0xF100, 0L);
  452. }!!
  453.  
  454. /* Get a filename from the user in responds to menu event.
  455.    If the file has changed, check with the user.
  456.    Send a fileOpen message to do the work. */
  457. /* Respond to menu choice to create a new project. */
  458. Def fileNew(self)
  459. {
  460.   if checkClean(self)
  461.     if gw
  462.       close(gw);
  463.     endif;
  464.     fileName := nil;
  465.     dirty := nil;  
  466.     setProject(self, new(Project));
  467.     checkMenuItem(self, PW_AUTOCALC);
  468.     setAutoCalc(project, true);
  469.     setText(self, appName(self));   
  470.     editInfo(project);
  471.     invalidate(self);
  472.   endif;
  473. }!!
  474.  
  475. /* Prompt the user for the filename to open.
  476.    Use the new combo box type of file dialog. */
  477. Def fileOpenAs(self | dlg, file, reader)
  478. {
  479.   if checkClean(self)
  480.     dlg := new(FileDialog, "*."+loadString(PW_EXTENSION));
  481.     if runModal(dlg, FILE_BOX, self) == IDOK
  482.       fileName := loadFile(dlg);    
  483.       fileOpen(self, fileName);
  484.     endif;
  485.   endif;
  486. }!!
  487.  
  488. /* Open the file named fName and read a project from disk.
  489.    If a DOS error occurs (like file not found) then stop.
  490.    Uses the Language Extensions I object storage facility. 
  491.    This method copies the file into a stream so that it
  492.    can read faster.  Also, the old project, file and stream
  493.    are set to nil as soon as possible to free up memory. */
  494. Def fileOpen(self, fName | dlg, file, strm, reader)
  495. {
  496.   showWaitCurs();                       /* this takes a while */
  497.   if gw
  498.     close(gw);                          /* close old GanttWindow */
  499.   endif;      
  500.   file := new(File);                    /* open the file etc. */
  501.   setName(file, fName);
  502.   open(file, 0);
  503.   if checkError(self, file) == 0        /* no DOS errors */
  504.     project := nil;                     /* free up memory */        
  505.   
  506.     strm := streamOver(copyFrom(file, 0, length(file))); 
  507.     close(file);
  508.     setText(self, appName(self)+": " + fName);  
  509.     reader := new(StoredObjectReader);
  510.     project := readFrom(reader, strm);  /* read the project */
  511.     strm := nil;                        /* free up memory */
  512.     setAutoCalc(project, true);         /* other settings */
  513.     checkMenuItem(self, PW_AUTOCALC);
  514.     dirty := nil;
  515.     invalidate(self);                   /* redraw the window */
  516.   else
  517.     fileName := nil;                    /* due to DOS error */
  518.   endif;
  519.   showOldCurs();                        /* all done */
  520. }!!
  521.  
  522. /* Respond to menu choice to save the file.  If the file
  523.    isn't yet named, prompt the user for a name. */
  524. Def fileSave(self)
  525. {
  526.   if fileName
  527.     fileSaveIt(self, fileName);
  528.   else
  529.     fileSaveAs(self);
  530.   endif;
  531. }!!
  532.  
  533. /* Save the project to disk with a new name. */
  534. Def fileSaveAs(self | dlg)
  535. {
  536.   if not(fileName)
  537.      fileName := getName(project)+"."+loadString(PW_EXTENSION);
  538.   endif;
  539.   dlg := new(InputDialog, loadString(PW_APPNAME),
  540.              loadString(PW_SAVEPROJ), fileName);
  541.   if runModal(dlg, INPUT_BOX, self) == IDOK         
  542.      fileName := getText(dlg);
  543.      fileSaveIt(self, fileName);
  544.   endif;
  545. }!!
  546.  
  547. /* Save the project to disk with the filename fName. 
  548.    If a DOS error occurs (like file not found) stop. 
  549.    Uses the Language Extensions I object storage facility. 
  550.    Note: this will not save any global variables!  */
  551. Def fileSaveIt(self, fName | file)
  552. {
  553.   showWaitCurs();                          /* this takes a while */
  554.   file := new(File);                       
  555.   setName(file, fName);
  556.   create(file);
  557.   if checkError(self, file) == 0           /* no DOS error */
  558.      setText(self, appName(self) + ": " + fileName);
  559.     storeOn(project, file, nil);           /* write to file */
  560.     close(file);
  561.     dirty := false;
  562.   else
  563.     fileName := nil;                       /* due to DOS error */
  564.   endif;
  565.   showOldCurs();
  566. }!!
  567.  
  568. /* Print a text summary of the project.
  569.    Uses the Printer class.  */
  570. Def print(self | prn)
  571. {
  572.   prn := new(Printer);
  573.   showWaitCurs();                              /* takes a while */
  574.   if start(prn, "Project", self)               /* start printing */
  575.      do(getInfoLines(project),
  576.        {using(line)
  577.         printLine(prn, line);
  578.      });
  579.      printLine(prn, " ");
  580.      printLine(prn, " ");
  581.      printLine(prn, loadString(PW_ACTIVT1)+":");
  582.      printLine(prn, loadString(PW_ACTIVT2));
  583.      printLine(prn, loadString(PW_ACTIVT3));
  584.      printLine(prn, "--------------------------------------------");
  585.      do(sortedActivities(project),
  586.        {using(aNode)
  587.         printLine(prn, getInfoLine(aNode));
  588.      });
  589.      if size(resources(project)) > 0
  590.        printLine(prn, " ");
  591.        printLine(prn, " ");
  592.        printLine(prn, loadString(PW_REST1) + ":");
  593.        printLine(prn, loadString(PW_REST2));
  594.        printLine(prn, loadString(PW_REST3));
  595.        printLine(prn, "------------------------------------------");
  596.        do(resources(project),
  597.          {using(aRes)
  598.           printLine(prn, getInfoLine(aRes));
  599.        });
  600.      endif;
  601.      finish(prn);                             /* all done */
  602.      showOldCurs();
  603.   else
  604.     showOldCurs();
  605.     beep();
  606.     errorBox(loadString(PW_PRINTERR1),loadString(PW_PRINTERR2));
  607.   endif;
  608. }!!
  609.  
  610. /* Print graphics charts */
  611. Def printGraphs(self)
  612. {
  613.   printWindow(self, 1);
  614. }!!
  615.  
  616. /* Copy bitmap to clipboard */
  617. Def clipChart(self)
  618. {
  619.   clipWindow(self, 1);
  620. }
  621.  
  622. /* Create a new Milestone */
  623. Def newMilestone(self)
  624. {
  625.   newActivity(self, Milestone);
  626. }!!
  627.  
  628. /* Create a new Task */
  629. Def newTask(self)
  630. {
  631.   newActivity(self, Task);
  632. }!!
  633.  
  634. /* Create a new PERTTask */
  635. Def newPERTTask(self)
  636. {
  637.   newActivity(self, PERTTask);
  638. }!!
  639.  
  640. /* Create a new activity based on a menu choice. 
  641.    The nodeClass should be passed in as Task, Milestone etc.
  642.    Return the new activity or nil if canceled. */
  643. Def newActivity(self, nodeClass | activity)
  644. {  
  645.   activity := new(nodeClass);
  646.   setNetwork(activity, project);
  647.   if editInfo(activity) == IDOK   /* let user connect it */
  648.     if pos(activity) = 0@0        /* still not connected */
  649.       activity.y := 1;            /* safe location */
  650.       resetPosn(getNetwork(activity), activity, 0@0);
  651.     endif;
  652.     dirty(self);                  /* redraw etc. */
  653.     ^activity;
  654.   endif;
  655.   ^nil;
  656. }!!
  657.  
  658. /* Delete a resource in response to menu choice. 
  659.    Returns the deleted resource or nil if canceled. */
  660. Def deleteResource(self | dlg, name, res)
  661.   dlg := new(InputDialog, loadString(PW_DELRES1),
  662.       loadString(PW_DELRES2), "");
  663.   if runModal(dlg, INPUT_BOX, self) == IDOK
  664.     name := getText(dlg);
  665.     if res := checkResExists(project, name) 
  666.        delete(res, project);
  667.        dirty(self);
  668.        ^res;
  669.     endif;    
  670.   endif;
  671.   ^nil;
  672. }!!
  673.  
  674. /* Delete an activity in response to menu choice. 
  675.    Returns the deleted node or nil if canceled. */
  676. Def deleteActivity(self | dlg, name, node)
  677.   dlg := new(InputDialog, loadString(PW_DELACT1),
  678.       loadString(PW_DELACT2), "");
  679.   if runModal(dlg, INPUT_BOX, self) == IDOK
  680.     name := getText(dlg);
  681.     if node := checkNodeExists(project, name) 
  682.        delete(node);
  683.        dirty(self);
  684.        ^node;
  685.     endif;
  686.   endif;
  687.   ^nil
  688. }!!
  689.  
  690. /* Edit a particular resource in response to menu choice.
  691.    For now, ask the user which one. Return the resource
  692.    or nil if canceled. */
  693. Def editResource(self | dlg, res)
  694. {
  695.  dlg := new(InputDialog, loadString(PW_VIEWRES1), loadString(PW_VIEWRES2),"");
  696.  if runModal(dlg, INPUT_BOX, self) == IDOK
  697.    if res := checkResExists(project, getText(dlg))
  698.       editInfo(res);
  699.       dirty(self);
  700.       ^res;
  701.    endif;
  702.  endif;  
  703.  ^nil;
  704. }!!
  705.  
  706. /* Show all of the resources as in a TextWindow. */
  707. Def showResources(self | tw)
  708. {
  709.   tw := new(TextWindow, self, nil, loadString(PW_REST1), nil);
  710.   show(tw, 1);  
  711.   printLine(tw, loadString(PW_SHOWRES2));
  712.   printLine(tw, "-----------------------------------------------");
  713.   do(resources(project),
  714.     {using(res)  
  715.      printLine(tw, getInfoLine(res));
  716.   });
  717. }!!
  718.  
  719. /* Show all of the activities in a TextWindow. */
  720. Def showActivities(self | tw)
  721. {
  722.   tw := new(TextWindow, self, nil, loadString(PW_ACTIVT1), nil);
  723.   show(tw, 1);  
  724.   printLine(tw, loadString(PW_SHOWACT2));
  725.   printLine(tw, "------------------------------------------");
  726.   do(sortedActivities(project),
  727.     {using(aNode)  
  728.      printLine(tw, getInfoLine(aNode));
  729.   });
  730. }!!
  731.  
  732. /* Respond to menu choice to edit the project */
  733. Def viewSummary(self)
  734. {
  735.   editInfo(project);
  736. }!!
  737.  
  738. /* If the user presses the home key, reset scroll posn. */
  739. Def home(self)
  740. {
  741.   hScrollPos := vScrollPos := 0;
  742.   Call SetScrollPos(hWnd, SB_HORZ, hScrollPos, 1);
  743.   Call SetScrollPos(hWnd, SB_VERT, vScrollPos, 1);
  744.   invalidate(self);
  745. }!!
  746.  
  747. /* If the right button is pressed, toggle the view
  748.    to allow zoom in and out */
  749. Def zoom(self)
  750. {
  751.    if view == #normal
  752.         setView(self, #small);
  753.    else
  754.         setView(self, #normal);
  755.    endif;
  756.    invalidate(self);
  757. }!!
  758.  
  759. /* Show the amount of memory available. */
  760. Def showRoom(self | temp)
  761.  temp := Call GlobalCompact(Call GlobalCompact(0)+16) / 1024;
  762.  
  763.  errorBox(loadString(PW_SHOWROOM1),
  764.    asString(temp) + loadString(PW_SHOWROOM2));
  765. }!!
  766.  
  767. /* Respond to menu choice to recalculate. */
  768. Def recalc(self)
  769. {
  770.   showWaitCurs();
  771.   recalc(project);
  772.   invalidate(self);
  773.   if gw
  774.    invalidate(gw);
  775.   endif;
  776.   showOldCurs();
  777. }!!
  778.  
  779. /* The ganttWindow has closed.  */
  780. Def closeGantt(self)
  781. {
  782.   gw := nil;
  783.   enableMenuItem(self, PW_VIEW_GANTT);
  784. }!!
  785.  
  786. /* Respond to menu choice to set display options.  The user
  787.    can select information to be displayed above or below
  788.    the nodes in the window.  */
  789. Def displaySettings(self | dlg)
  790. {
  791.   dlg := new(PWSetDialog);
  792.   if runModal(dlg, SETTING_BOX, self) == IDOK
  793.      invalidate(self);
  794.   endif;
  795. }!!
  796.  
  797. /* Handle menu choice to create a Gantt chart. 
  798.    Create the window large enough to hold all of
  799.    the activities, plus some extra space. */
  800. Def gantt(self | height)
  801. {
  802.   if screenSize()=640@200
  803.     height := 10
  804.   else
  805.     height := 20;
  806.   endif;
  807.   gw := new(GanttWindow, self, nil, loadString(PW_GANTT),
  808.             rect(asInt(x(screenSize())/3), 
  809.               max(y(screenSize())-(size(project)+5)*height,10),
  810.               x(screenSize()), y(screenSize())));
  811.   setProject(gw, project);
  812.   show(gw,1);
  813.   grayMenuItem(self, PW_VIEW_GANTT);
  814. }!!
  815.  
  816. /* Display help information from resource file. */
  817. Def help(self | dlg)
  818. {
  819.   dlg := new(Dialog);
  820.   checkRunModal(dlg, PW_HELP_BOX, self);
  821. }!!
  822.  
  823. /* Display Actor information from resource file. */
  824. Def aboutActor(self | dlg)
  825. {
  826.   dlg := new(Dialog);
  827.   checkRunModal(dlg, PW_ABOUT_ACTOR_BOX, self);
  828. }!!
  829.  
  830. /* Handles menu choice to set autocalc. */
  831. Def autoCalc(self)
  832. {
  833.   if autoCalc(project)
  834.     unCheckMenuItem(self, PW_AUTOCALC);
  835.     setAutoCalc(project, false);
  836.   else
  837.     checkMenuItem(self, PW_AUTOCALC);
  838.     setAutoCalc(project, true);
  839.     recalc(self);
  840.   endif;
  841. }!!
  842.  
  843. /* See if the user has double clicked on a box.
  844.    If so, bring up a dialog for editing. Return the
  845.    activity or nil if canceled. */
  846. Def WM_LBUTTONDBLCLK(self, wp, lp | dPoint, activity)
  847. {
  848.   dPoint := windowToDisplay(self, asPoint(lp));
  849.   activity := displayLookup(project, dPoint);
  850.   if activity                       /* logically true if found */
  851.     if editInfo(activity) == IDOK   /* user clicked on activity */
  852.       dirty(self);                  /* changes were made */
  853.       ^activity;
  854.     endif;
  855.   else                              /* false if nothing found */
  856.     beep();                         /* user clicked on dead space */
  857.   endif;
  858.   ^nil;
  859. }!!
  860.  
  861. /* If the right button is pressed, toggle the view
  862.    to allow zoom in and out */
  863. Def WM_RBUTTONDOWN(self, wp, lp)
  864. {
  865.   zoom(self);
  866. }!!
  867.  
  868. /* Trap keyboard events to simulate mouse. Cursor keys move
  869.    the cursor and scroll, return and F2 edit an activity.
  870.    Note anything defined as an accelerator will NOT cause
  871.    a WM_KEYDOWN message.  The keys W, X, A, D can also be 
  872.    used to move the cursor. */
  873. Def WM_KEYDOWN(self, wp, lp | pos, x, y, activity, max, dict)
  874.   pos := getCursorPos(self);    /* client coords */
  875.   x := x(pos);
  876.   y := y(pos);
  877.  
  878.   select
  879.     case wp == VK_UP or wp == asInt('W')
  880.       y := y - boxHeight*2;
  881.     endCase
  882.     case wp == VK_DOWN or wp == asInt('X')
  883.       y := y + boxHeight*2;
  884.     endCase
  885.     case wp == VK_LEFT or wp == asInt('A')
  886.       x := x - activWidth;
  887.     endCase
  888.     case wp == VK_RIGHT or wp == asInt('D')
  889.       x := x + activWidth;
  890.     endCase
  891.     case wp == VK_RETURN or wp == VK_F2  
  892.       WM_LBUTTONDBLCLK(self, 1, asLong(pos));
  893.     endCase    
  894.   endSelect;
  895.   
  896.  /* If the cursor is moving off screen, scroll. */
  897.   
  898.   select
  899.     case y < 0 
  900.       y := boxHeight;
  901.       WM_VSCROLL(self, SB_LINEUP, 1);
  902.     endCase
  903.     case y > max:=maxVisRow*boxHeight*2
  904.       y := max - boxHeight;
  905.       WM_VSCROLL(self, SB_LINEDOWN, 1);
  906.     endCase
  907.   endSelect;
  908.   
  909.   select
  910.     case x < 0 
  911.       x := boxHSpace;
  912.       WM_HSCROLL(self, SB_LINEUP, 1);
  913.     endCase
  914.     case x > max:=maxVisCol*activWidth
  915.       x := max - boxWidth;
  916.       WM_HSCROLL(self, SB_LINEDOWN, 1);
  917.     endCase
  918.   endSelect;
  919.  
  920.   setCursorPos(self, point(x,y));
  921. }!!
  922.  
  923. /* Trap scrolling.  Adjust as necesary.
  924.    The wp is the scroll code, the lp gives posn. */
  925. Def WM_HSCROLL(self, wp, lp | scroll)
  926.   select
  927.     case wp == SB_LINEUP 
  928.        scroll := -1;
  929.     endCase
  930.     case wp == SB_LINEDOWN 
  931.        scroll := 1;
  932.     endCase
  933.     case wp == SB_PAGEUP
  934.        scroll := negate(maxVisCol);
  935.     endCase;
  936.     case wp == SB_PAGEDOWN
  937.        scroll := maxVisCol;
  938.     endCase;
  939.     case wp == SB_THUMBPOSITION
  940.        hScrollPos := 0; scroll := low(lp);
  941.     endCase;
  942.     default
  943.        scroll := nil;
  944.   endSelect;
  945.  
  946.   if scroll 
  947.     hScrollPos := hScrollPos + scroll;    /* adjust */
  948.     hScrollPos := min(PW_MAX_COLS, max(0, hScrollPos));
  949.     Call SetScrollPos(hWnd, SB_HORZ, hScrollPos, 1);
  950.     invalidate(self);
  951.   endif;
  952. }!!
  953.  
  954. /* Trap scrolling.  Adjust as necesary.
  955.    The wp is the scroll code, the lp gives posn. */
  956. Def WM_VSCROLL(self, wp, lp | scroll)
  957.   select
  958.     case wp == SB_LINEUP 
  959.        scroll := -1;
  960.     endCase
  961.     case wp == SB_LINEDOWN 
  962.        scroll := 1;
  963.     endCase
  964.     case wp == SB_PAGEUP
  965.        scroll := negate(maxVisRow);
  966.     endCase;
  967.     case wp == SB_PAGEDOWN
  968.        scroll := maxVisRow;
  969.     endCase;
  970.     case wp == SB_THUMBPOSITION
  971.        vScrollPos := 0; scroll := low(lp);
  972.     endCase;
  973.   endSelect;
  974.  
  975.   if scroll
  976.     vScrollPos := vScrollPos + scroll;    /* adjust */
  977.     vScrollPos := min(PW_MAX_ROWS, max(0, vScrollPos));
  978.     Call SetScrollPos(hWnd, SB_VERT, vScrollPos, 1);
  979.     invalidate(self);
  980.   endif;
  981. }!!
  982.  
  983.  
  984. /* Begin dragging to allow the user to draw a line
  985.    that will connect two boxes.  Setup the anchorPt and
  986.    dragDC to allow dragging to do the drawing.
  987.    BW 02/05/89 */
  988. Def beginDrag(self, wp, aPt | dPoint, activity, dMode)
  989. {
  990.   dPoint := windowToDisplay(self, aPt);
  991.   activity := displayLookup(project, dPoint);
  992.   if activity   /* logically true if found */
  993.     anchorPt := aPt;
  994.     dragDC := getContext(self);
  995.     dMode := Call SetROP2(dragDC,7);
  996.     Call SelectObject(dragDC,Call GetStockObject(6));
  997.   endif;
  998. }!!
  999.  
  1000. /* Do the drag and draw the feedback.
  1001.    BW 02/05/89 */
  1002. Def drag(self, wp, aPt )
  1003. { if dragDC then
  1004.     if oldPt cand (oldPt <> aPt)
  1005.       then moveTo(anchorPt,dragDC);
  1006.         lineTo(oldPt,dragDC);
  1007.     endif;
  1008.     oldPt := aPt;
  1009.     moveTo(anchorPt,dragDC);
  1010.     lineTo(aPt,dragDC);
  1011.   endif;
  1012. }!!
  1013.  
  1014. /* Finish the drag connection of two tasks.
  1015.    Create a new task if necessary. */
  1016. Def endDrag(self, wp, aPt | dPoint1, dPoint2, activity1, activity2)
  1017. {
  1018.   if dragDC then
  1019.     dPoint2 := windowToDisplay(self, aPt);
  1020.     activity2 := displayLookup(project, dPoint2);
  1021.     if activity2  /* logically true if found */
  1022.       dPoint1 := windowToDisplay(self,anchorPt);
  1023.       activity1 := displayLookup(project, dPoint1);
  1024.       if activity1 <> activity2
  1025.         connect(project,getName(activity1),
  1026.           getName(activity2));
  1027.         invalidate(self);
  1028.       endif;
  1029.     else /* maybe the user wants a new node */
  1030.       if activity2 := newActivity(self,Task) then
  1031.         dPoint1 := windowToDisplay(self,anchorPt);
  1032.         activity1 := displayLookup(project, dPoint1);
  1033.         connect(project,getName(activity1),
  1034.           getName(activity2));
  1035.         invalidate(self);
  1036.       else
  1037.         moveTo(anchorPt,dragDC); /* erase last line*/
  1038.         lineTo(oldPt,dragDC);
  1039.       endif;
  1040.     endif;
  1041.     releaseContext(self,dragDC); /* done drawing */
  1042.     dragDC := nil;
  1043.     oldPt := nil;
  1044.   endif;
  1045. }!!
  1046.  
  1047.